/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package nio;

import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**

 @author zztbak01
 */
public class Serwer extends Thread {

	Selector selector;
	static int port = 9999;
	SelectionKey selectionKey;
	ServerSocketChannel channel;
	HashMap<String, File> pliki = new HashMap<String, File>();
	public boolean wellInitialized = false;

	public Serwer() {
		try {
			selector = Selector.open();
			channel = ServerSocketChannel.open();
			channel.configureBlocking(false);
			InetSocketAddress isa = new InetSocketAddress(port);
			channel.socket().bind(isa);
			selectionKey = channel.register(selector, SelectionKey.OP_ACCEPT);
			wellInitialized = true;
		} catch (IOException ex) {
			Logger.getLogger(Serwer.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	public boolean isWellInitialized() {
		return wellInitialized;
	}

//	public static void main(String[] args) throws IOException {
//		new Serwer().start();
//		String filename = "plik1.test";
//		File file = new File(filename);
//		FileWriter fw = new FileWriter(file);
//		fw.write("Tekst testowy 123");
//		fw.close();
//		pliki.put(filename, file);
//		pliki.put("CLient.class", new File("build/classes/nio/Client.class"));
//	}
	private Set<String> listFiles() {
		return pliki.keySet();
	}

	private void send(SocketChannel sc, ByteBuffer bb) throws IOException {
		while (bb.remaining() > 0) {
			sc.write(bb);
		}
	}

	private void send(SocketChannel sc, String s) throws IOException {
		if (!s.endsWith("\n")) {
			s = s + "\n";
		}
		byte[] message = s.getBytes();
		send(sc, (ByteBuffer) ByteBuffer.allocate(message.length).put(message).flip());
	}

	void acceptSelectionKey(SelectionKey key) {
		SocketChannel sc;
		try {
			sc = ((ServerSocketChannel) key.channel()).accept();
			sc.configureBlocking(false);
			sc.register(selector, SelectionKey.OP_READ, SelectionKey.OP_WRITE);
			System.out.println("Got connection from " + sc);
		} catch (IOException ex) {
			System.out.println("Connecion closed");
			key.cancel();
			Logger.getLogger(Serwer.class.getName()).log(Level.SEVERE, null, ex);
		}
	}

	void readSelectionKey(SelectionKey key) {
		SocketChannel sc = (SocketChannel) key.channel();
		Scanner scanner = new Scanner(sc);
		try {
			String line = scanner.nextLine();
			String[] napisy = line.split(" ");
			switch (napisy[0].charAt(0)) {
				case 'l': //list
					StringBuilder sb = new StringBuilder();
					for (String filename : listFiles()) {
						sb.append(filename).append("\n");
					}
					send(sc, sb.append("\n").toString());
					break;
				case 'g': //get
					if (pliki.containsKey(napisy[1])) {
						File f = pliki.get(napisy[1]);
						send(sc, f.length() + "\n");
						key.attach(new FileSender(f, sc));
						key.interestOps(SelectionKey.OP_WRITE);
					} else {
						send(sc, "Nie ma takiego pliku\n");
					}
					break;
				case 'e': //end
					send(sc, "Koniec połączenia\n");
					scanner.close();
					key.cancel();
					break;
				default:
					send(sc, "Unknown command\n");
					break;
			}
		} catch (Exception ex) {
			scanner.close();
			key.cancel();
		}
	}

	void writeToSelectionKey(SelectionKey key) {
		FileSender fileSender = (FileSender) key.attachment();
		try {
			if (!fileSender.buffer.hasRemaining()) {
				fileSender.readNextPart();
			}
			fileSender.sendNextPart();
			if (fileSender.fis.available() == 0 && !fileSender.buffer.hasRemaining()) {
				key.attach(null);
				key.interestOps(SelectionKey.OP_READ);
			}
		} catch (IOException ex) {
			try {
				fileSender.socket.close();
			} catch (IOException ex1) {
				Logger.getLogger(Serwer.class.getName()).log(Level.SEVERE, null, ex1);
			}
			key.cancel();
		}
	}

	@Override
	public void run() {
		System.out.println("Startuję serwer do wysyłania plików");
		while (true) {
			try {
				if (selector.select() > 0) {
					Set<SelectionKey> keys = selector.selectedKeys();
					Iterator<SelectionKey> keyIterator = keys.iterator();
					while (keyIterator.hasNext()) {
						SelectionKey key = keyIterator.next();
						keyIterator.remove();
						if (key.isAcceptable()) {
							acceptSelectionKey(key);
						} else if (key.isReadable()) {
							readSelectionKey(key);

						} else if (key.isWritable() && key.attachment() != null) {
							writeToSelectionKey(key);
						}
					}
				}
			} catch (IOException ex) {
				Logger.getLogger(Serwer.class.getName()).log(Level.SEVERE, null, ex);
			}
		}
	}
}
